/*
 * Copyright: (C) 2014 EAST
 *            All rights reserved.
 *   Version:  1.0.0(07/30/2014)
 *    Author:  fulinux <fulinux@sina.com>
 * ChangeLog:  1, Release initial version on "07/30/2014 01:52:51 PM"
 */
 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <signal.h>
#include <stdint.h>
#include <pthread.h>
#include <canbus.h>

static volatile int running = 1;

void sigterm(int signo)
{
    running = 0;
}

/*
 * can[0] 接收，can[1] 发送,两者互不影响.
 */
int main (int argc, char **argv)
{
    int i, j;
    uint8_t *message;
    struct timeval timeout;
    struct can_filter filter[2];
    struct pgn_filter pfilter[2];
    struct sndlist sndlist[4];
    struct can_eframe *can[2];

    for(i = 0; i < 2; i++){
        can[i] = can_init("vcan0", 6, 0, 0xE5, 0xF4);
        if(NULL == can[i]){
            perror("CAN INIT");
            return -1;
        }

        if(-1 == can_setdebug(can[i], TRUE)){
            perror("SET DEBUG");
            return -1;
        }
    }

    message = (uint8_t *)malloc(512 * sizeof(uint8_t));
    message[0] = 1;
    message[1] = 2;
    message[5] = 5;
    message[6] = 6;
    message[11] = 11;
    message[22] = 22;
    message[33] = 33;
    message[44] = 44;
    message[400] = 40;
    message[500] = 50;
    message[510] = 31;
    message[511] = 51;

    sndlist[0].pgn = 0x500;
    sndlist[0].len = 4;
    sndlist[0].prio = 6;
    sndlist[0].msg = message;
    sndlist[0].itv.it_value.tv_sec = 0;
    sndlist[0].itv.it_value.tv_usec = 0;
    sndlist[0].itv.it_interval.tv_sec = 0;
    sndlist[0].itv.it_interval.tv_usec = 200000; /* 200ms */

    /* 该报文在50ms后开始周期性发送, 周期是300ms. */
    sndlist[1].pgn = 0x600;
    sndlist[1].len = 17;
    sndlist[1].prio = 6;
    sndlist[1].msg = message + 30;
    sndlist[1].itv.it_value.tv_sec = 0;
    sndlist[1].itv.it_value.tv_usec = 500000;
    sndlist[1].itv.it_interval.tv_sec = 0;
    sndlist[1].itv.it_interval.tv_usec = 300000; /* 300ms */

    /* 该报文在100ms后开始周期性发送, 周期是400ms. */
    sndlist[2].pgn = 0x700;
    sndlist[2].len = 8;
    sndlist[2].prio = 6;
    sndlist[2].msg = message + 399;
    sndlist[2].itv.it_value.tv_sec = 1;
    sndlist[2].itv.it_value.tv_usec = 0;
    sndlist[2].itv.it_interval.tv_sec = 0;
    sndlist[2].itv.it_interval.tv_usec = 400000; /* 400ms */

    sndlist[3].pgn = 0x800;
    sndlist[3].len = 13;
    sndlist[3].prio = 6;
    sndlist[3].msg = message + 500;
    sndlist[3].itv.it_value.tv_sec = 1;
    sndlist[3].itv.it_value.tv_usec = 500000;
    sndlist[3].itv.it_interval.tv_sec = 0;
    sndlist[3].itv.it_interval.tv_usec = 500000; /* 500ms */

    can_cycle2snd(can[1], sndlist, sizeof(sndlist));

    /* 
     * 过滤标准帧中PF值等于0x01、0x03和0x04的帧. 
     * 在某些应用中pf中的值向左移动8bit时的值就
     * 是PGN的值. 综合标准帧和扩展帧的过滤规则
     * 知: PGN值等于768的帧都可以被过滤.
     */
    filter[0].can_id = CAN_EFF_FLAG | (0x100 << 8);
    filter[0].can_mask = CAN_EFF_FLAG | 0xFF0000;
    filter[1].can_id = CAN_EFF_FLAG | (0x300 << 8);
    filter[1].can_mask = CAN_EFF_FLAG | 0xFF0000;

    /* 
     * 过滤扩展帧时需要首先过滤扩展帧的标志,
     * 下面过滤扩展帧中PGN值等于512和768的帧. 
     */
    pfilter[0].pgn = 0x200;
    pfilter[0].mask = 0xFF00;
    pfilter[1].pgn = 0x400;
    pfilter[1].mask = 0xFF00;
    if(-1 == can_setfilter(can[0], filter, sizeof(filter), pfilter, sizeof(pfilter))){
        perror("SET FILTER");
        return -1;
    }

    for(;running;){
        timeout.tv_sec = 5;
        timeout.tv_usec = 0;
        if(can_recv(can[0], &timeout) == -1){
            perror("CAN RECV");
        }else{
            printf ("\n");
            printf ("pgn = %d\n", can[0]->pgn);
            for(i = 0, j = 0; i < can[0]->len; i++, j++){
                if(j > 7){
                    j = 0;
                    printf ("\n");
                }
                printf ("[%03d]", can[0]->msg[i]);
            }
            printf ("\n");
            printf ("\n");
        }
    }

    for(i = 0; i < 2; i++){
        can[i] = can_init("vcan0", 6, 0, 0xF4, 0xE5);
        if(NULL == can[i]){
            perror("CAN INIT");
            return -1;
        }

        if(-1 == can_setdebug(can[i], TRUE)){
            perror("SET DEBUG");
            return -1;
        }
    }

    signal(SIGTERM, sigterm);
    signal(SIGHUP, sigterm);
    signal(SIGINT, sigterm);

    for(;running;){
        ;
    }

    for(i = 0; i < 2; i++){
        if(-1 == can_exit(can[i])){
            perror("CAN EXIT");
            exit(-1);
        }
    }

    return 0;
} /* ----- End of main() ----- */
